<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<link rel="stylesheet" href="../style/journal.css" type="text/css" />
<style type="text/css"><!--
.googleadsense {
	margin: 2px;
	padding: 0px;
//--></style><script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-65008-1";
urchinTracker();
</script><title>modperl Filter Part1</title>
</head>
<body>
<a href="index.html">Journal</a>(2005) | <a href="../blog/"><b>Blog</b></a>(2006) | <a href="http://www.fayland.org/cgi-bin/random_link.pl">RandomLink</a> | <a href="AboutFayland.html">WhoAmI</a> | <a href="LiveBookmark.html">LiveBookmark</a> | <a href="http://www.fayland.org/">HomePage</a>
<p><&lt;Previous: <a href="Encode_Guess_And_Han.html">Lingua::Han::Utils 和 Encode::Guess</a>&nbsp;&nbsp;>>Next: <a href="birthday_18.html">Happy 18th birthday, Perl</a></p>
<h1>modperl Filter Part1</h1>
<div class='content'>
<p>Category: <a href='mod_perl.html'>mod_perl</a> &nbsp; Keywords: <b>modperl filter</b></p>我写过 <a href='Template_builtin_Filters.html'>Template builtin Filters</a> 和 <a href='Template_customized_Filte.html'>Template customized Filters</a>，这是 <a href="http://www.template-toolkit.org">TT</a> 的过滤器。<br /><a href="http://perl.apache.org">modperl</a> 也有它自己的过滤器。过滤器的含义都是一样的，接受一些数据，改变它，然后返回这些数据。<br />这在你不能对原始数据做一些改变时特别有用。<br />我的打算是先介绍 modperl 的内置案例，然后自己写几个 filter.<p />首先 modperl 的 filter 分为两种：PerlInputFilterHandler 和 PerlOutputFilterHandler 。<br />我先用官方文档的 <a href='http://apache.perl.org/docs/2.0/user/handlers/filters.html'>Input and Output Filters</a> 来解释一下 filter 的一般写法。<br /><pre>#file:MyApache2/FilterObfuscate.pm<br />#--------------------------------<br />package MyApache2::FilterObfuscate;<p />use strict;<br />use warnings;<br />use Apache2::Filter ();<br />use Apache2::RequestRec ();<br />use APR::Table ();<br />use Apache2::Const -compile => qw(OK);<p />use constant BUFF_LEN => 1024;<p />sub handler {<br /> &nbsp; &nbsp;my $f = shift;<br />  <br /> &nbsp; &nbsp;unless ($f->ctx) {<br /> &nbsp; &nbsp; &nbsp; &nbsp;$f->r->headers_out->unset('Content-Length');<br /> &nbsp; &nbsp; &nbsp; &nbsp;$f->ctx(1);<br /> &nbsp; &nbsp;}<br />  <br /> &nbsp; &nbsp;while ($f->read(my $buffer, BUFF_LEN)) {<br /> &nbsp; &nbsp; &nbsp; &nbsp;$buffer =~ s/[\r\n]//g;<br /> &nbsp; &nbsp; &nbsp; &nbsp;$f->print($buffer);<br /> &nbsp; &nbsp;}<br />  <br /> &nbsp; &nbsp;return Apache2::Const::OK;<br />}<br />1;</pre>这个过滤器是将文件里的 \r\n 换行去掉。实际上一般你要去掉 \r\n 的时候要注意如 pre 这样的标签时必须将 \r\n 转为 br 或者不去掉。这里我们只是简单的写一下，没什么实际意义。<br />应用的话：<br /><pre>&lt;Files ~ "\.html"><br /> &nbsp; &nbsp;PerlOutputFilterHandler MyApache2::FilterObfuscate<br />&lt;/Files></pre>对于所有的 html 使用此过滤器。<br /><ul>下面解释下：<br /><li>my $f = shift; 这里是用 $f 而不是 $r 是因为这里传进来的是 filter 对象而不是 request 对象。<br /><li>$f->ctx 用于设置 filter 的上下文变量。它在每一个请求时初始化，请求结束时 undef 掉。如果有多个 filter 的话，它可以在这几个 filter 共享一些变量。<br /><pre>unless ($f->ctx) {<br /> &nbsp; &nbsp;$f->r->headers_out->unset('Content-Length');<br /> &nbsp; &nbsp;$f->ctx(1);<br />}</pre>第一行测试是否已经设置了 ctx, 如果没有设置的话，说明是第一次访问，因为我们将在接下来对内容做一些缩水（去掉了换行），所以必须重新设置 Content-Length, 否则的话浏览器将期待更多的内容，这样会出错。当 unset Content-Length 后，我们将 ctx 设置为 1. 这样下次访问就不需要重新 unset Content-Length 了。<br />关于 $f->ctx 的更多解释，查看 <a href="http://search.cpan.org/perldoc?Apache2::Filter">Apache2::Filter</a><br /><li>while ($f->read(my $buffer, BUFF_LEN)) {<br />read 用于读进 BUFF_LEN 长度的内容。设置 BUFF_LEN 是怕内容太大，一次读入可能会死机。这里的 BUFF_LEN 已经用 <br />use constant BUFF_LEN => 1024; 设置过了。<br />这个和处理 CGI 上传文件是相似的。<br /><li>$buffer =~ s/[\r\n]//g;$f->print($buffer); 做一些改变，然后输出它。<br /><li>return Apache2::Const::OK; 返回值。这里的返回值可以是 Apache2::Const::OK 或者是 Apache2::Const::DECLINED。二者的区别可以查看 <a href='modperl_http_cycle.html'>modperl 服务器的运行阶段和句柄</a><br /></ul><h3>一次请求中调用了多次 filter 句柄</h3>在继续之前，我们得学习下 Apache 处理输出的内在性质。<br />Apache 并不是将所有的内容存在一个块中，而是将内容分为很多个 buckets，然后用一个所谓的 Bucket Brigades 连起来。详细的查看官方文档，<a href='http://perl.apache.org/docs/2.0/user/handlers/intro.html#Bucket_Brigades'>Bucket Brigades</a>. 我也不是很清楚。<br />诸位只需要知道在一次请求中，我们会调用多次同一个 filter 句柄就可以了。<br />这就是为什么我们要设置 $f->ctx(1); 的原因。<br />如果你想知道到底调用了多少次该句柄的话，可以这么写 handler:<br /><pre>sub handler {<br />    my $f = shift;<p />    my $ctx = $f->ctx;<br />    $ctx->{invoked}++;<br />    $f->ctx($ctx);<br />    warn "filter was invoked $ctx->{invoked} times\n";<br />  <br />    return Apache2::Const::DECLINED;<br />}</pre>$f->ctx->{invoked} 来纪录调用了多少次，每调用一次增加一。<br />先读取 my $ctx = $f->ctx; 再增加 $ctx->{invoked}++; 最后赋值纪录回去 $f->ctx($ctx);<br />这就是 $f->ctx 的一般用法。<h3>$f->seen_eos</h3>我们可以用 $f->ctx 来测试是否是第一次访问，同时我们可以用 $f->seen_eos 来测试是否是最后一次访问该过滤器句柄。可能的代码如下：<br /><pre>if ($f->seen_eos) {<br />    finalize($f);<br />}</pre>自定义子过程 finalize 用于处理一些结尾工作。<h3>Stay stun</h3>See u next time!</div>
<p><&lt;Previous: <a href="Encode_Guess_And_Han.html">Lingua::Han::Utils 和 Encode::Guess</a>&nbsp;&nbsp;>>Next: <a href="birthday_18.html">Happy 18th birthday, Perl</a></p>
<p><strong>Options:</strong> <a href='http://del.icio.us/post?title=modperl%20Filter%20Part1&url=http://www.fayland.org/journal/modperl_Filter_part1.html'>+Del.icio.us</a></p>
<strong>Related items</strong>
<ul><li><a href='modperl_helloworld.html'>modperl Apache2::HelloWorld</a> < <span class='digit'>2005-11-16 23:24:07</span> ></li><li><a href='modperl_http_cycle.html'>modperl 服务器的运行阶段和句柄</a> < <span class='digit'>2005-11-22 15:33:08</span> ></li><li><a href='modperl_PerlTransHandler.html'>modperl 的 PerlTransHandler 应用</a> < <span class='digit'>2005-11-23 22:24:02</span> ></li><li><a href='modperl_PerlAuthenHandler.html'>modperl 的用户验证</a> < <span class='digit'>2005-11-26 00:08:37</span> ></li><li><a href='Template_builtin_Filters.html'>Template builtin Filters</a> < <span class='digit'>2005-12-09 23:14:04</span> ></li><li><a href='Template_customized_Filte.html'>Template customized Filters</a> < <span class='digit'>2005-12-10 01:10:15</span> ></li></ul>
Created on <span class="digit">2005-12-18 14:47:29</span>, Last modified on <span class="digit">2005-12-18 15:06:50</span><br />
Copyright 2004-2005 All Rights Reserved. Powered by <a href="Eplanet.html">Eplanet</a> && <a href='http://catalyst.perl.org'>Catalyst</a> 5.62.
</body>
</html>